# 背景

问题来源:如果使用 webpack,比如运行 npx webpack . 会在每次构建结束后控制台输出编译耗时。这时可能就会发出疑问,webpack 是如何计算编译时间的呢?

asset main.js 1.4 KiB [compared for emit] (name: main)
./index.js 56 bytes [built] [code generated]
./sum.js 41 bytes [built] [code generated]
webpack 5.74.0 compiled successfully in 75 ms
1
2
3
4

# 回答问题

  1. stats.endTime - stats.startTime

  1. stats.toJson().time

image.png

文章只对第一种方式获取到编译时间的过程进行了详述,另一种留给读者实践验证~

# 查看源码

# 思路

思路:从后往前分析,从结果出发,看调用堆栈

# 调试过程

说明:以下调试代码是使用 Webpack 的 Node.js API 实现,具体使用可参考官方文档。

https://webpack.docschina.org/api/node/ (opens new window)

https://webpack.docschina.org/api/node/#run (opens new window)

首先准备代码

build.js

const webpack = require('webpack')
const path = require('path')

function build1() {
  return webpack({
    entry: {
      index: './index.js',
      test: './test.js'
    },
    output: {
      path: path.resolve(__dirname, 'build'),
      filename: '[name].js'
    },
    mode: 'none'
  })
}

build1()
  .run((err, stat) => {
    const startTime = stat.startTime
    const endTime = stat.endTime
    console.log("构建时间", endTime - startTime);
    // console.log("构建时间", stat.endTime - stat.startTime);
  })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

index.js

console.log('index---');
1

test.js

function test() {
  console.log('test---');
}

test()
1
2
3
4
5

开始调试

(1)因为我们知道 .run 内的回调能拿到 err 和 stat 参数,那就将断点先打到回调函数体内,如这里的第 20 行,通过调用堆栈去找 stat。在 JavaScript Debug Terminal 执行 node build.js,代码运行到断点处,这时不要着急,看左侧的调用堆栈。

(2)点击堆栈中第二行,到了 callback 的调用位置,明确目标,我们要找到 stats 是怎么传递的,于是关注到 callback 在 finalCallback 函数体内,这个函数接收到 stats 参数,所以要去找这个函数的调用位置;

(3)继续点击堆栈第三行,这时就来到调用 finalCallback 的位置,这里传递了 stats

(4)这时可以不用在堆栈找了,因为我们已经定位到位置,现在需要去搜索 stats 变量在哪里定义和赋值的

这里发现有一个 startTime,再去找它的声明和赋值的位置

(5)在(4)的分析中,有一个关键的位置 new Stats(compilation),可以跟进去看一下,ctrl+click

进到了 Stats.js 中,猜想是通过这两个方法拿到 startTime/endTime

(6)现在已经比较清晰了,可以在以上分析中的关键代码中打断点,然后执行,进去看看每个断点位置的执行情况

(7)还有一个简单的验证方式,直接在 20 行打断点,然后单步调试

这样直接进到 Stats.js 中

# 小结

实际上就是在开始编译和编译结束的时候,通过 Date.now() 获取对应的时间戳,放在了 Stats 对象上(其实还是通过 compilation 拿到的)

Compiler.js

// ...
const startTime = Date.now() // 获取开始编译时间
// ...
compilation.startTime = startTime;
compilation.endTime = Date.now() // 获取编译结束时间
// ...
1
2
3
4
5
6

# 参考

上次更新: 2024年3月10日星期日上午10点19分